<template>
    <el-table-v2 :columns="columns" :data="data" :width="props.width" :height="props.height" :row-height="props.rowHeight" fixed />
</template>

<script setup lang="tsx">
import { useDictionaryStore } from '@store/modules/dictionary';
import { CheckboxValueType, ElImage, ElSwitch, ElInput, ElDatePicker, type Column, ElCheckbox } from 'element-plus';
import { checkTypeText, checkTypeLink, checkTypeBoolean, checkTypeNumber } from '@utils/check';
import { checkRole } from '@utils/permission';
import { FunctionalComponent } from 'vue';
import pictureError from '@assets/img/common/pictureError.png';
import dayjs from 'dayjs';

onMounted(() => {
    // console.log('🚀 ~ onMounted ~ props:', props);
    // console.log('🚀 ~ onMounted ~ props.otherColumn:', props.otherColumn);
    // console.log('🚀 ~ onMounted ~ props.disable:', props.disable);
});

/* ********************通用属性******************** */
// 父组件传来的属性
const props = defineProps<{
    width: number;
    height: number;
    rowHeight: number;
    data: any[];
    otherColumn: { [key: string]: Column<any> };
    disable?: string[];
}>();
// 父组件传来的方法
const emit = defineEmits<{
    updateData: [id: string, field: Column['dataKey'], value: string | boolean | number | any[]];
}>();
// 使用字典缓存
const useDictionary = useDictionaryStore();
// 被选择的表格数据id
const selected = defineModel<string[]>({ required: true });

/* ********************el-table-v2 表格属性******************** */
// image函数式组件
type ImageCellProps = {
    src: string;
};
const ImageCell: FunctionalComponent<ImageCellProps> = ({ src }) => {
    return <ElImage src={src} style={{ width: props.rowHeight }} fit={'cover'} />;
};
// checkbox函数式组件
type CheckBoxCellProps = {
    value: boolean;
    intermediate?: boolean;
    onChange: (value: CheckboxValueType) => void;
};
const CheckBoxCell: FunctionalComponent<CheckBoxCellProps> = ({ value, intermediate = false, onChange }) => {
    return <ElCheckbox size={'large'} modelValue={value} indeterminate={intermediate} onChange={onChange} />;
};
// input函数式组件
type InputCessProps = {
    value: string;
    type: string;
    // 在 Input 值改变时触发
    onInput: (value: string) => void;
    // 当选择器的输入框获得焦点时触发
    onFocus: () => void;
    // 当选择器的输入框失去焦点时触发
    onBlur: () => void;
};
const InputCell: FunctionalComponent<InputCessProps> = ({ value, type, onFocus, onBlur, onInput }) => {
    return <ElInput modelValue={value} type={type} onFocus={onFocus} onBlur={onBlur} onInput={onInput} />;
};
// 生成columns
const generateColumns = async () => {
    // 清空columns
    columns.length = 0;

    // 获取首个数据字段的key
    const keys = Object.keys(props.data.length == 0 ? '' : props.data[0]);

    // 查找父组件是否有禁用的key -- 有权限则放行/选择性展示相似的属性（比如含税价、不含税价）
    if (props.disable !== undefined) {
        for (let index = 0; index < props.disable.length; index++) {
            const dis = props.disable[index];
            // 如果是编号列，则放行
            if (dis == 'priority') break;
            // 如果是禁用的key，则删除
            if (keys.indexOf(dis) !== -1) {
                keys.splice(keys.indexOf(dis), 1);
            }
        }
    }

    // 获取父元素传来的columns
    const otherKeys = Object.keys(Object.keys(props.otherColumn).length == 0 ? '' : props.otherColumn);

    // 编号列标识 -- 用于需要排序的表
    let prioritySymbol = otherKeys.indexOf('priority') !== -1 ? true : false;

    // 遍历通过的数据keys
    for (let index = 0; index < keys.length; index++) {
        const key = keys[index];
        // 父组件是否交付其他column
        if (otherKeys.length === 0) {
            // 如果父组件没有交付其他colum，则生成column
            generateColumn(key);
        } else {
            // 如果父组件交付其他column，则查询是否需要覆盖原生的column
            if (otherKeys.indexOf(key) !== -1) {
                // 生成父组件传来的column
                const item = props.otherColumn[key];
                columns.push(item);
            } else {
                // 生成自定义column
                generateColumn(key);
            }
        }
    }

    // 如果父组件没有传递了priority编号,则生成序号列
    if (!prioritySymbol) {
        // 如果禁用了order，则跳过
        if (props.disable?.indexOf('order') == -1) {
            // 生成表格列后，插入序号列
            columns.unshift({
                key: 'order',
                dataKey: 'order',
                width: 60,
                align: 'center',
                title: '序号',
            });
        }
    }

    // 生成序号列后，插入选择列
    columns.unshift({
        key: 'selection',
        dataKey: 'selection',
        width: 60,
        align: 'center',
        cellRenderer: ({ rowData }) => {
            const onChange = (value: CheckboxValueType) => {
                if (value) {
                    // 添加被选数据
                    selected.value.push(rowData._id);
                    // 去重
                    selected.value = [...new Set(selected.value)];
                } else {
                    // 删除被选数据
                    const index = selected.value.indexOf(rowData._id);
                    index !== -1 ? selected.value.splice(index, 1) : '';
                }
                rowData.checked = value;
            };
            return <CheckBoxCell value={rowData.checked} onChange={onChange} />;
        },
        headerCellRenderer: () => {
            const onChange = (value: CheckboxValueType) => {
                // 全不选
                selected.value.length = 0;
                if (!value) {
                    data.forEach((item) => (item.checked = value as boolean));
                } else {
                    // 全选
                    data.forEach((item) => {
                        selected.value.push(item._id);
                        item.checked = value as boolean;
                    });
                }
            };
            const allSelected = data.every((row: any) => row.checked); // 初始全选检测
            const containsChecked = data.some((row: any) => row.checked); // 初始中间态检测

            return <CheckBoxCell value={allSelected} intermediate={containsChecked && !allSelected} onChange={onChange} />;
        },
    });
};
// input原始值
let inputOriginValue = '';
// 生成单个column
const generateColumn = (key: string) => {
    // 获取key在字典中的数据
    const { definition, roles, type, width } = useDictionary.getDictionaryUseField(key);
    // 判断是否为空
    if (definition == '') return;
    // 判断当前用户是否有权限查看该字段
    if (checkRole(roles)) {
        switch (type) {
            case 'text':
                columns.push({
                    key: key,
                    dataKey: key,
                    width: width,
                    align: 'center',
                    title: definition,
                    cellRenderer: ({ rowData, column }) => {
                        // 特殊字段转换
                        if (key == 'createdAt' || key == 'updatedAt') {
                            rowData[column.dataKey!] = dayjs(rowData[column.dataKey!]).format('YYYY-MM-DD HH:mm:ss');
                        }
                        // 判断是否为文本类型
                        if (checkTypeText(rowData[column.dataKey!]) || checkTypeNumber(rowData[column.dataKey!])) {
                            return <span class={'text'}>{rowData[column.dataKey!]}</span>;
                        } else {
                            return '';
                        }
                    },
                });
                break;
            case 'input':
                columns.push({
                    key: key,
                    dataKey: key,
                    width: width,
                    align: 'center',
                    title: definition,
                    cellRenderer: ({ rowData, column }) => {
                        // 文本类型检测 + 数字类型检测
                        if (!checkTypeText(rowData[column.dataKey!]) && !checkTypeNumber(rowData[column.dataKey!])) return '';
                        // 输入框编辑模式
                        const onEnterEditMode = () => {
                            rowData.editing = true;
                            inputOriginValue = rowData[column.dataKey!];
                        };

                        // 输入框内容改变时触发
                        const onInput = (value: string) => {
                            rowData[column.dataKey!] = value;
                        };

                        // 输入框退出编辑模式 -- 更新到服务器
                        const onExitEditMode = () => {
                            // 输入框退出编辑模式
                            rowData.editing = false;
                            // 对比新旧值
                            if (rowData[column.dataKey!] !== inputOriginValue) {
                                // 更新到服务器
                                emit('updateData', rowData._id, column.dataKey!, rowData[column.dataKey!]);
                            }
                        };

                        // 判断是否为文本类型
                        return rowData.editing ? (
                            <InputCell
                                value={rowData[column.dataKey!]}
                                type={'text'}
                                onFocus={onEnterEditMode}
                                onBlur={onExitEditMode}
                                onInput={onInput}
                            />
                        ) : (
                            <div
                                class={
                                    rowData[column.dataKey!] === ''
                                        ? 'table-v2-inline-editing-trigger-trim text'
                                        : 'table-v2-inline-editing-trigger text'
                                }
                                onClick={onEnterEditMode}
                            >
                                {rowData[column.dataKey!]}
                            </div>
                        );
                    },
                });
                break;
            case 'textarea':
                columns.push({
                    key: key,
                    dataKey: key,
                    width: width,
                    align: 'center',
                    title: definition,
                    cellRenderer: ({ rowData, column }) => {
                        // 文本类型检测
                        if (!checkTypeText(rowData[column.dataKey!]) && !checkTypeNumber(rowData[column.dataKey!])) return '';
                        // 输入框编辑模式
                        const onEnterEditMode = () => {
                            rowData.editing = true;
                            inputOriginValue = rowData[column.dataKey!];
                        };

                        // 输入框内容改变时触发
                        const onInput = (value: string) => {
                            rowData[column.dataKey!] = value;
                        };

                        // 输入框退出编辑模式 -- 更新到服务器
                        const onExitEditMode = () => {
                            // 输入框退出编辑模式
                            rowData.editing = false;
                            // 对比新旧值
                            if (rowData[column.dataKey!] !== inputOriginValue) {
                                // 更新到服务器
                                emit('updateData', rowData._id, column.dataKey!, rowData[column.dataKey!]);
                            }
                        };

                        // 判断是否为文本类型
                        return rowData.editing ? (
                            <InputCell
                                value={rowData[column.dataKey!]}
                                type={'textarea'}
                                onFocus={onEnterEditMode}
                                onBlur={onExitEditMode}
                                onInput={onInput}
                            />
                        ) : (
                            <div
                                class={
                                    rowData[column.dataKey!] === ''
                                        ? 'table-v2-inline-editing-trigger-trim text'
                                        : 'table-v2-inline-editing-trigger text'
                                }
                                onClick={onEnterEditMode}
                            >
                                {rowData[column.dataKey!]}
                            </div>
                        );
                    },
                });
                break;
            case 'image':
                columns.push({
                    key: key,
                    dataKey: key,
                    width: width,
                    align: 'center',
                    title: definition,
                    cellRenderer: ({ rowData, column }) => {
                        // 判断是否为图片类型
                        return checkTypeLink(rowData[column.dataKey!]) ? (
                            <ImageCell src={rowData[column.dataKey!]}></ImageCell>
                        ) : (
                            <ImageCell src={pictureError}></ImageCell>
                        );
                    },
                });
                break;
            case 'switch':
                columns.push({
                    key: key,
                    dataKey: key,
                    width: width,
                    align: 'center',
                    title: definition,
                    cellRenderer: ({ rowData, column }) => {
                        // 转换为布尔值
                        const boo = checkTypeBoolean(rowData[column.dataKey!]);
                        // switch 状态发生变化时的回调函数
                        const onChange = (value: boolean) => {
                            rowData[column.dataKey!] = value;
                            // 更新到服务器
                            emit('updateData', rowData._id, column.dataKey!, rowData[column.dataKey!]);
                        };
                        return <ElSwitch modelValue={boo} inline-prompt onChange={onChange} activeText={'激活'} inactiveText={'禁用'} />;
                    },
                });
                break;
            case 'date':
                columns.push({
                    key: key,
                    dataKey: key,
                    width: width,
                    align: 'center',
                    title: definition,
                    cellRenderer: ({ rowData, column }) => {
                        // 转换为时间戳
                        const date = dayjs(rowData[column.dataKey!]).valueOf();

                        // 用户确认选定的值时触发
                        const onChange = (value: number) => {
                            rowData[column.dataKey!] = value;
                            // 更新到服务器
                            emit('updateData', rowData._id, column.dataKey!, rowData[column.dataKey!]);
                        };

                        return <ElDatePicker type={'date'} modelValue={date} onChange={onChange} />;
                    },
                });
                break;
            case 'datetime':
                columns.push({
                    key: key,
                    dataKey: key,
                    width: width,
                    align: 'center',
                    title: definition,
                    cellRenderer: ({ rowData, column }) => {
                        // 转换为时间戳
                        const date = dayjs(rowData[column.dataKey!]).valueOf();

                        // 用户确认选定的值时触发
                        const onChange = (value: number) => {
                            rowData[column.dataKey!] = value;
                            // 更新到服务器
                            emit('updateData', rowData._id, column.dataKey!, rowData[column.dataKey!]);
                        };

                        return <ElDatePicker type={'datetime'} modelValue={date} onChange={onChange} />;
                    },
                });
                break;
            default:
                break;
        }
    }
};
// column
const columns = reactive<Column<any>[]>([]);

// 数据
const data = reactive<any>(props.data);

// 监听data的变化
watch(
    () => props.data,
    () => {
        // 父组件异步传来数据时生成表格列
        generateColumns();
    },
    { deep: true }
);

// 监听disable的变化
watch(
    () => props.disable,
    () => {
        // 父组件异步传来禁用时生成表格列
        generateColumns();
    },
    { deep: true }
);
</script>

<style>
.table-v2-inline-editing-trigger {
    border: 1px transparent dotted;
    padding: 4px;
}

.table-v2-inline-editing-trigger-trim {
    border: 1px transparent dotted;
    width: 50px;
    height: 30px;
}

.table-v2-inline-editing-trigger:hover {
    border-color: var(--el-color-primary);
}

.table-v2-inline-editing-trigger-trim:hover {
    border-color: var(--el-color-primary);
}

.text {
    word-break: break-all; /* 或者使用 word-break: break-word; */
    overflow-wrap: break-word; /* 兼容旧浏览器使用 word-wrap: break-word; */
}
</style>
